﻿using Ionic.Zip;
using Pdf2epub.Interfaces;
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;

namespace Pdf2epub.Epub
{
    public class Epub : EpubBase
    {
        private SearchOption m_DirectorySearchOption = SearchOption.TopDirectoryOnly;
        private IProjectContext m_ProjectContext;

        public Epub(IProjectContext projectContext, string epubDirectory, TocOptions option)
            : this(epubDirectory)
        {
            m_ProjectContext = projectContext;
            tocOption = option;
        }

        public Epub(string epubDirectory)
        {
            Directory = epubDirectory;
        }

        public SearchOption DirectorySearchOption
        {
            get { return m_DirectorySearchOption; }
            set { m_DirectorySearchOption = value; }
        }

        private string Directory { get; set; }

        protected override void DoMainActions()
        {
            BuildEpubStructure();
            GenerateContainerFile();

            //ParseContentFilesByDefault();
            ParseFilesByDefault();
            CreateTitlePage();

            GenerateMetadataAndTocFiles(Directory);

            isDirty = true;
        }

        private void CreateTitlePage()
        {
            if (string.IsNullOrEmpty(m_ProjectContext.ProjectConfiguration.CoverImagePath))
                return;

            string coverFile = Path.Combine(m_ProjectContext.ProjectConfiguration.ImageOutputPath, m_ProjectContext.ProjectConfiguration.CoverImagePath);
            if (!File.Exists(coverFile))
                return;

            Image coverImage = Image.FromFile(coverFile);
            int imageWidth = coverImage.Size.Width;
            int imageHeight = coverImage.Size.Height;

            XmlDocument xmlDoc = new XmlDocument();

            XmlElement htmlElement = xmlDoc.CreateElement("html");
            htmlElement.SetAttribute("xmlns", "http://www.w3.org/1999/xhtml");
            htmlElement.SetAttribute("xml:lang", "en");
            XmlNode htmlNode = xmlDoc.AppendChild(htmlElement);

            XmlElement headerElement = xmlDoc.CreateElement("head");
            XmlNode headerNode = htmlNode.AppendChild(headerElement);

            XmlElement metaHttpElement = xmlDoc.CreateElement("meta");
            metaHttpElement.SetAttribute("http-equiv", "Content-Type");
            metaHttpElement.SetAttribute("content", "text/html; charset=utf-8");
            headerNode.AppendChild(metaHttpElement);

            XmlElement calibreCoverElement = xmlDoc.CreateElement("meta");
            calibreCoverElement.SetAttribute("name", "calibre:cover");
            calibreCoverElement.SetAttribute("content", "true");
            headerNode.AppendChild(metaHttpElement);

            XmlElement metaTitleElement = xmlDoc.CreateElement("title");
            metaTitleElement.InnerText = "Cover";
            headerNode.AppendChild(metaTitleElement);

            XmlElement metaStyleElement = xmlDoc.CreateElement("style");
            metaStyleElement.SetAttribute("type", "text/css");

            XmlText styleText = xmlDoc.CreateTextNode("@page {padding: 0pt; margin:0pt}\nbody { text-align: center; padding:0pt; margin: 0pt; }\nimg { max-width: 100%; max-height: 100%; }");
            metaStyleElement.AppendChild(styleText);

            headerNode.AppendChild(metaStyleElement);

            XmlElement bodyElement = xmlDoc.CreateElement("body");
            XmlNode bodyNode = htmlNode.AppendChild(bodyElement);

            XmlElement divElement = xmlDoc.CreateElement("div");
            divElement.SetAttribute("id", m_ProjectContext.ProjectConfiguration.CoverImagePath);
            XmlNode divNode = bodyNode.AppendChild(divElement);

            //XmlElement svgElement = xmlDoc.CreateElement("svg");
            //svgElement.SetAttribute("xmlns", "http://www.w3.org/2000/svg");
            //svgElement.SetAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
            //svgElement.SetAttribute("version", "1.1");
            //svgElement.SetAttribute("width", "100%");
            //svgElement.SetAttribute("height", "100%");
            //svgElement.SetAttribute("viewBox", string.Format("0 0 {0} {1}", imageWidth, imageHeight));
            //svgElement.SetAttribute("preserveAspectRatio", "none");
            //XmlNode svgNode = divNode.AppendChild(svgElement);

            XmlElement imageElement = xmlDoc.CreateElement("img");
            imageElement.SetAttribute("src", "cover.jpg");
            imageElement.SetAttribute("alt", "cover");

            //svgNode.AppendChild(imageElement);
            divNode.AppendChild(imageElement);

            string tempCoverPath = Path.Combine(Path.GetTempPath(), "cover.xhtml");
            xmlDoc.Save(tempCoverPath);

            file.AddFile(coverFile, "");
            file.AddFile(tempCoverPath, "");

            Metadata.CoverPageCreated = true;
        }

        private string[] GetPatterns(string patterns)
        {
            return patterns.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
        }

        private void ParseContentFiles(TocOptions option, params string[] patterns)
        {
            if (patterns == null || patterns.Length == 0) return;
            foreach (string filePath in patterns.SelectMany(pattern => System.IO.Directory.GetFiles(Directory, pattern, m_DirectorySearchOption)))
            {
                if (file.ContainsEntry(Structure.Directories.ContentFolder + "/" + Path.GetFileName(filePath))) continue;
                ZipEntry entry = file.AddFile(filePath, Structure.Directories.ContentFolder);

                string title = Path.GetFileNameWithoutExtension(filePath);
                if (option == TocOptions.ByTitleTag)
                {
                    string text = File.ReadAllText(filePath);
                    title = Regex.Match(text, "<title>\\s*.*\\s*</title>").Value;
                    title = Regex.Match(title, ">\\s*.*\\s*<").Value.Trim('>', '<', ' ', '\t', '\n');
                }
                else if (option == TocOptions.ByFirstH1Header)
                {
                    title = ChapterHelpers.FindFirstH1Title(filePath);
                }
                entry.Comment = title;
            }
        }

        private void ParseContentFilesByDefault()
        {
            ParseContentFiles(tocOption, GetPatterns(Resources.ContentPatterns));
        }

        private void ParseFilesByDefault()
        {
            ParseContentFilesByDefault();
            ParseImagesByDefault();
            ParseStylesheets();
        }

        private void ParseImages(params string[] patterns)
        {
            if (patterns == null || patterns.Length == 0) return;
            foreach (string filePath in patterns.SelectMany(pattern => System.IO.Directory.GetFiles(Directory, pattern, m_DirectorySearchOption)))
            {
                if (!file.ContainsEntry(Structure.Directories.ImageFolderFullPath + "/" + Path.GetFileName(filePath)))
                    file.AddFile(filePath, Structure.Directories.ImageFolderFullPath);
            }
        }

        private void ParseImagesByDefault()
        {
            ParseImages(GetPatterns(Resources.ImagePatterns));
        }

        private void ParseStylesheets()
        {
            foreach (string filePath in System.IO.Directory.GetFiles(Directory, "*.css", m_DirectorySearchOption))
            {
                if (!file.ContainsEntry(Structure.Directories.CssFolderFullPath + "/" + Path.GetFileName(filePath)))
                    file.AddFile(filePath, Structure.Directories.CssFolderFullPath);
            }
        }
    }
}